page.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. "use client";
  2. import {fetchApi} from "@/app/_modules/func";
  3. import {DeleteOutlined, ExclamationCircleFilled, PlusOutlined, ReloadOutlined,} from "@ant-design/icons";
  4. import type {ActionType, ProColumns, ProFormInstance,} from "@ant-design/pro-components";
  5. import {PageContainer, ProTable,} from "@ant-design/pro-components";
  6. import type {GetProp, UploadProps} from "antd";
  7. import {Button, message, Modal, Space, Tag, Upload,} from "antd";
  8. import {useRouter} from "next/navigation";
  9. import {faCheck, faToggleOff, faToggleOn, faXmark,} from "@fortawesome/free-solid-svg-icons";
  10. import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
  11. import {useRef, useState} from "react";
  12. type FileType = Parameters<GetProp<UploadProps, "beforeUpload">>[0];
  13. const { Dragger } = Upload;
  14. export type OptionType = {
  15. label: string;
  16. value: string | number;
  17. };
  18. export default function RoleAuth({ params }: { params: { roleid: string } }) {
  19. const { push } = useRouter();
  20. const roleId = params.roleid;
  21. //表格列定义
  22. const columns: ProColumns[] = [
  23. {
  24. title: "用户名称",
  25. dataIndex: "userName",
  26. order: 2,
  27. },
  28. {
  29. title: "用户昵称",
  30. dataIndex: "nickName",
  31. search: false,
  32. },
  33. {
  34. title: "邮箱",
  35. dataIndex: "email",
  36. search: false,
  37. },
  38. {
  39. title: "手机号",
  40. dataIndex: "phonenumber",
  41. order: 1,
  42. },
  43. {
  44. title: "状态",
  45. dataIndex: "status",
  46. search: false,
  47. valueEnum: {
  48. 0: {
  49. text: "正常",
  50. status: "0",
  51. },
  52. 1: {
  53. text: "停用",
  54. status: "1",
  55. },
  56. },
  57. render: (text, record) => {
  58. return (
  59. <Space>
  60. <Tag
  61. color={record.status == 0 ? "green" : "red"}
  62. icon={
  63. record.status == 0 ? (
  64. <FontAwesomeIcon icon={faCheck} />
  65. ) : (
  66. <FontAwesomeIcon icon={faXmark} />
  67. )
  68. }
  69. >
  70. {text}
  71. </Tag>
  72. </Space>
  73. );
  74. },
  75. },
  76. {
  77. title: "创建时间",
  78. dataIndex: "createTime",
  79. valueType: "dateTime",
  80. search: false,
  81. },
  82. {
  83. title: "操作",
  84. key: "option",
  85. search: false,
  86. render: (_, record) => {
  87. if (record.userId != 1)
  88. return [
  89. <Button
  90. key="deleteBtn"
  91. type="link"
  92. danger
  93. icon={<DeleteOutlined />}
  94. onClick={() => onClickRemoveAuth(record)}
  95. >
  96. 取消授权
  97. </Button>,
  98. ];
  99. },
  100. },
  101. ];
  102. //未分配授权用户列定义
  103. const unAllocateColumns: ProColumns[] = [
  104. {
  105. title: "用户名称",
  106. dataIndex: "userName",
  107. order: 2,
  108. },
  109. {
  110. title: "用户昵称",
  111. dataIndex: "nickName",
  112. search: false,
  113. },
  114. {
  115. title: "邮箱",
  116. dataIndex: "email",
  117. search: false,
  118. },
  119. {
  120. title: "手机号",
  121. dataIndex: "phonenumber",
  122. order: 1,
  123. },
  124. {
  125. title: "状态",
  126. dataIndex: "status",
  127. search: false,
  128. valueEnum: {
  129. 0: {
  130. text: "正常",
  131. status: "0",
  132. },
  133. 1: {
  134. text: "停用",
  135. status: "1",
  136. },
  137. },
  138. render: (text, record) => {
  139. return (
  140. <Space>
  141. <Tag
  142. color={record.status == 0 ? "green" : "red"}
  143. icon={
  144. record.status == 0 ? (
  145. <FontAwesomeIcon icon={faCheck} />
  146. ) : (
  147. <FontAwesomeIcon icon={faXmark} />
  148. )
  149. }
  150. >
  151. {text}
  152. </Tag>
  153. </Space>
  154. );
  155. },
  156. },
  157. {
  158. title: "创建时间",
  159. dataIndex: "createTime",
  160. valueType: "dateTime",
  161. search: false,
  162. },
  163. ];
  164. //查询角色授权数据
  165. const getRoleAllocate = async (params: any, sorter: any, filter: any) => {
  166. const searchParams = {
  167. roleId: roleId,
  168. pageNum: params.current,
  169. ...params,
  170. };
  171. delete searchParams.current;
  172. const queryParams = new URLSearchParams(searchParams);
  173. Object.keys(sorter).forEach((key) => {
  174. queryParams.append("orderByColumn", key);
  175. if (sorter[key] === "ascend") {
  176. queryParams.append("isAsc", "ascending");
  177. } else {
  178. queryParams.append("isAsc", "descending");
  179. }
  180. });
  181. const body = await fetchApi(
  182. `/api/system/role/authUser/allocatedList?${queryParams}`,
  183. push
  184. );
  185. if (body !== undefined) {
  186. return body;
  187. }
  188. };
  189. //查询角色未授权数据
  190. const getRoleUnallocate = async (params: any, sorter: any, filter: any) => {
  191. const searchParams = {
  192. roleId: roleId,
  193. pageNum: params.current,
  194. ...params,
  195. };
  196. delete searchParams.current;
  197. const queryParams = new URLSearchParams(searchParams);
  198. Object.keys(sorter).forEach((key) => {
  199. queryParams.append("orderByColumn", key);
  200. if (sorter[key] === "ascend") {
  201. queryParams.append("isAsc", "ascending");
  202. } else {
  203. queryParams.append("isAsc", "descending");
  204. }
  205. });
  206. const body = await fetchApi(
  207. `/api/system/role/authUser/unallocatedList?${queryParams}`,
  208. push
  209. );
  210. if (body !== undefined) {
  211. return body;
  212. }
  213. };
  214. //取消授权按钮是否可用,选中行时才可用
  215. const [rowCanRemoveAuth, setCanRemoveAuth] = useState(false);
  216. //点击批量取消授权按钮
  217. const onClickBatchRemoveAuth = () => {
  218. Modal.confirm({
  219. title: "系统提示",
  220. icon: <ExclamationCircleFilled />,
  221. content: `确定要取消选中用户的角色授权吗?`,
  222. onOk() {
  223. executeBatchRemoveRoleAuth();
  224. },
  225. onCancel() {},
  226. });
  227. };
  228. //点击取消授权按钮
  229. const onClickRemoveAuth = (record: any) => {
  230. const userId = record.userId;
  231. Modal.confirm({
  232. title: "系统提示",
  233. icon: <ExclamationCircleFilled />,
  234. content: `确定要取消用户“${record.userName}”的角色授权吗?`,
  235. onOk() {
  236. executeRemoveRoleAuth(userId);
  237. },
  238. onCancel() {},
  239. });
  240. };
  241. //执行批量取消用户角色授权
  242. const executeBatchRemoveRoleAuth = async () => {
  243. const data = {
  244. roleId: roleId,
  245. userIds: selectedRowKeys.join(","),
  246. };
  247. const body = await fetchApi(
  248. `/api/system/role/authUser/cancelAll?${new URLSearchParams(data)}`,
  249. push,
  250. {
  251. method: "PUT",
  252. }
  253. );
  254. if (body !== undefined) {
  255. if (body.code == 200) {
  256. message.success("批量取消授权成功");
  257. } else {
  258. message.error(body.msg);
  259. }
  260. setSelectedRowKeys([]);
  261. //刷新表格
  262. if (actionRef.current) {
  263. actionRef.current.reload();
  264. }
  265. }
  266. };
  267. //执行取消用户角色授权
  268. const executeRemoveRoleAuth = async (userId: any) => {
  269. const data = {
  270. roleId: roleId,
  271. userId: userId,
  272. };
  273. const body = await fetchApi("/api/system/role/authUser/cancel", push, {
  274. method: "PUT",
  275. headers: {
  276. "Content-Type": "application/json",
  277. },
  278. body: JSON.stringify(data),
  279. });
  280. if (body !== undefined) {
  281. if (body.code == 200) {
  282. message.success("取消授权成功");
  283. } else {
  284. message.error(body.msg);
  285. }
  286. //刷新表格
  287. if (actionRef.current) {
  288. actionRef.current.reload();
  289. }
  290. }
  291. };
  292. //选中行操作
  293. const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
  294. const rowSelection = {
  295. onChange: (newSelectedRowKeys: React.Key[]) => {
  296. setSelectedRowKeys(newSelectedRowKeys);
  297. setCanRemoveAuth(newSelectedRowKeys && newSelectedRowKeys.length > 0);
  298. },
  299. };
  300. //未授权用户选中行操作
  301. const [selectedRowKeysUnallocate, setSelectedRowKeysUnallocate] = useState<
  302. React.Key[]
  303. >([]);
  304. const rowSelectionUnallocate = {
  305. onChange: (newSelectedRowKeys: React.Key[]) => {
  306. setSelectedRowKeysUnallocate(newSelectedRowKeys);
  307. },
  308. };
  309. //是否展示分配用户对话框
  310. const [showUnallocateModal, setShowUnallocateModal] = useState(false);
  311. //展示分配用户对话框
  312. const onClickShowModal = () => {
  313. if (unallocateActionRef.current) {
  314. unallocateActionRef.current.reload();
  315. }
  316. setShowUnallocateModal(true);
  317. };
  318. //确认分配新的用户
  319. const confirmAddUnallocate = async () => {
  320. const data = {
  321. roleId: roleId,
  322. userIds: selectedRowKeysUnallocate.join(","),
  323. };
  324. const body = await fetchApi(
  325. `/api/system/role/authUser/selectAll?${new URLSearchParams(data)}`,
  326. push,
  327. {
  328. method: "PUT",
  329. }
  330. );
  331. if (body !== undefined) {
  332. if (body.code == 200) {
  333. message.success(body.msg);
  334. } else {
  335. message.error(body.msg);
  336. }
  337. }
  338. setSelectedRowKeysUnallocate([]);
  339. if (unallocateActionRef.current) {
  340. unallocateActionRef.current.reload();
  341. }
  342. console.log(selectedRowKeysUnallocate);
  343. if (actionRef.current) {
  344. actionRef.current.reload();
  345. }
  346. setShowUnallocateModal(false);
  347. };
  348. //取消分配用户
  349. const cancelAddUnallocate = () => {
  350. setShowUnallocateModal(false);
  351. };
  352. //搜索栏显示状态
  353. const [showSearch, setShowSearch] = useState(true);
  354. //action对象引用
  355. const actionRef = useRef<ActionType>(null);
  356. //表单对象引用
  357. const formRef = useRef<ProFormInstance>(null!);
  358. //未分配用户列表action对象引用
  359. const unallocateActionRef = useRef<ActionType>(null);
  360. //当前默认条数
  361. const defaultPageSize = 10;
  362. return (
  363. <PageContainer
  364. header={{
  365. title: "分配用户",
  366. onBack(e) {
  367. push("/system/role");
  368. },
  369. }}
  370. >
  371. <ProTable
  372. formRef={formRef}
  373. rowKey="userId"
  374. rowSelection={{
  375. selectedRowKeys,
  376. ...rowSelection,
  377. }}
  378. columns={columns}
  379. request={async (params: any, sorter: any, filter: any) => {
  380. // 表单搜索项会从 params 传入,传递给后端接口。
  381. const data = await getRoleAllocate(params, sorter, filter);
  382. if (data !== undefined) {
  383. return Promise.resolve({
  384. data: data.rows,
  385. success: true,
  386. total: data.total,
  387. });
  388. }
  389. return Promise.resolve({
  390. data: [],
  391. success: true,
  392. });
  393. }}
  394. pagination={{
  395. defaultPageSize: defaultPageSize,
  396. showQuickJumper: true,
  397. showSizeChanger: true,
  398. }}
  399. search={
  400. showSearch
  401. ? {
  402. defaultCollapsed: false,
  403. searchText: "搜索",
  404. }
  405. : false
  406. }
  407. dateFormatter="string"
  408. actionRef={actionRef}
  409. toolbar={{
  410. actions: [
  411. <Button icon={<PlusOutlined />} key="allocate" type="primary" onClick={onClickShowModal}>
  412. 添加用户
  413. </Button>,
  414. <Button
  415. key="unallocate"
  416. danger
  417. icon={<DeleteOutlined />}
  418. disabled={!rowCanRemoveAuth}
  419. onClick={() => onClickBatchRemoveAuth()}
  420. >
  421. 批量取消授权
  422. </Button>,
  423. ],
  424. settings: [
  425. {
  426. key: "switch",
  427. icon: showSearch ? (
  428. <FontAwesomeIcon icon={faToggleOn} />
  429. ) : (
  430. <FontAwesomeIcon icon={faToggleOff} />
  431. ),
  432. tooltip: showSearch ? "隐藏搜索栏" : "显示搜索栏",
  433. onClick: (key: string | undefined) => {
  434. setShowSearch(!showSearch);
  435. },
  436. },
  437. {
  438. key: "refresh",
  439. tooltip: "刷新",
  440. icon: <ReloadOutlined />,
  441. onClick: (key: string | undefined) => {
  442. if (actionRef.current) {
  443. actionRef.current.reload();
  444. }
  445. },
  446. },
  447. ],
  448. }}
  449. />
  450. <Modal
  451. title={`选择用户`}
  452. width={1000}
  453. open={showUnallocateModal}
  454. onOk={confirmAddUnallocate}
  455. onCancel={cancelAddUnallocate}
  456. >
  457. <ProTable
  458. rowKey="userId"
  459. rowSelection={{
  460. selectedRowKeys: selectedRowKeysUnallocate,
  461. ...rowSelectionUnallocate,
  462. }}
  463. columns={unAllocateColumns}
  464. request={async (params: any, sorter: any, filter: any) => {
  465. // 表单搜索项会从 params 传入,传递给后端接口。
  466. const data = await getRoleUnallocate(params, sorter, filter);
  467. if (data !== undefined) {
  468. return Promise.resolve({
  469. data: data.rows,
  470. success: true,
  471. total: data.total,
  472. });
  473. }
  474. return Promise.resolve({
  475. data: [],
  476. success: true,
  477. });
  478. }}
  479. pagination={{
  480. defaultPageSize: defaultPageSize,
  481. showQuickJumper: true,
  482. showSizeChanger: true,
  483. }}
  484. search={
  485. showSearch
  486. ? {
  487. defaultCollapsed: false,
  488. searchText: "搜索",
  489. }
  490. : false
  491. }
  492. dateFormatter="string"
  493. actionRef={unallocateActionRef}
  494. toolbar={{
  495. actions: [],
  496. settings: [],
  497. }}
  498. />
  499. </Modal>
  500. </PageContainer>
  501. );
  502. }